package com.only4play.filter;

import com.only4play.http.RequestWrapper;
import jakarta.annotation.Nonnull;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;

import java.io.IOException;

/**
 * @author liyuncong
 * @version 1.0
 * @file RequestFilter
 * @brief RequestFilter
 * @details RequestFilter
 * @date 2024-02-01
 * <p>
 * Edit History
 * ----------------------------------------------------------------------------
 * DATE                     NAME               DESCRIPTION
 * 2024-02-01               liyuncong          Created
 */
@Slf4j
@Component
public class RequestFilter extends OncePerRequestFilter {

    /**
     * ControllerAdvice拦截Filter抛出的异常
     * <link><a href="https://www.cnblogs.com/flgb/p/15922254.html">ControllerAdvice拦截Filter抛出的异常</a></link>
     */
    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    /**
     * 接口签名+接口请求参数加密
     * <p>
     * 1、前端通过非对称算法按照约定好的格式对请求参数和请求体进行加密；
     * 2、前端根据加密好的参数以及时间戳、随机值按照约定好的格式进行方法签名；
     * 3、后端根据方法签名进行校验，校验失败则返回错误信息；
     * 4、后端通过非对称算法按照约定好的格式对加密参数进行解密，将解密数据放回到请求里，重写http请求；
     * 5、后端处理合法请求；
     *
     * @param request
     * @param response
     * @param filterChain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(
        @Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull FilterChain filterChain
    ) throws ServletException, IOException {

        try {
            RequestWrapper wrapper = new RequestWrapper(request);
            // do signature repeat check

            doFilter(wrapper, response, filterChain);
        } catch (Exception exception) {
            resolver.resolveException(request, response, null, exception);
        }
    }

    /**
     * 签名防重校验
     *
     * @param request http请求
     */
    public void checkRepeatAndSignature(RequestWrapper request) {
        // 检查是否需要使用客户端的时间戳来进行防重校验
    }

}
